package com.ddw.meedeeuh.shared.database.sqlite;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.almworks.sqlite4java.SQLiteConnection;
import com.almworks.sqlite4java.SQLiteJob;
import com.ddw.meedeeuh.shared.database.DatabaseCallback;

/**
 * Represents a helper class for sqlite jobs, the class handles
 * logging on specific sqlite events and performs exception handling
 * for asynchronous method callbacks
 * @author cmcnicholas
 *
 * @param <T> the job result type for a successful query
 */
public abstract class SQLiteJobHelper<T> extends SQLiteJob<T> {

	private final long stamp = System.nanoTime();
	private final Logger logger;
	private final String name;
	private final DatabaseCallback<T> callback;

	/**
	 * Creates a new sqlite job helper instance
	 * @param callback the callback to respond to or null if no response required
	 * @param name the name of the job for logging purposes
	 * @param logger the logger to log with
	 */
	public SQLiteJobHelper(DatabaseCallback<T> callback, String name, Logger logger) {
		if(name == null) {
			throw new IllegalArgumentException("The name parameter cannot be null");
		}
		if(logger == null) {
			throw new IllegalArgumentException("The logger parameter cannot be null");
		}

		this.name = name;
		this.callback = callback == null ? new DatabaseCallback<T>() {

			@Override
			public void onSuccess(T result) {
				// Do nothing
			}

			@Override
			public void onFailure(Throwable e) {
				// Do nothing
			}

		} : callback;
		this.logger = logger;
	}

	/**
	 * Gets the callback function
	 * @return a database callback instance
	 */
	private DatabaseCallback<T> getCallback() {
		return this.callback;
	}

	/**
	 * Gets the name of the job
	 * @return a job name
	 */
	private String getName() {
		return this.name;
	}

	/**
	 * Gets the timestamp of when the job was created
	 * @return a timestamp
	 */
	private long getStamp() {
		return this.stamp;
	}

	/**
	 * Gets the logger to log to
	 * @return a logger instance
	 */
	private Logger getLogger() {
		return this.logger;
	}

	@Override
	public String toString() {
		return String.format("<%d:%s>", this.getStamp(), this.getName());
	}

	@Override
	protected void jobCancelled() throws Throwable {
		getLogger().finest(String.format("SQL Job %s cancelled", toString()));
		super.jobCancelled();
	}

	@Override
	protected void jobStarted(SQLiteConnection connection) throws Throwable {
		getLogger().finest(String.format("SQL Job %s started", toString()));
		super.jobStarted(connection);
	}

	@Override
	protected void jobFinished(T result) throws Throwable {
		// Check error on finished
		if(getError() != null) {
			getLogger().log(Level.SEVERE, String.format("SQL Job %s failed", toString()), getError());
			getCallback().onFailure(getError());
			return;
		}

		// Otherwise job finished successfully
		getLogger().finer(String.format("SQL Job %s finished successfully", toString()));
		getCallback().onSuccess(result);
	}

}